Skip to content

Package constants#8916

Open
Noremos wants to merge 78 commits intoFirebirdSQL:masterfrom
Noremos:metacache_package_constants
Open

Package constants#8916
Noremos wants to merge 78 commits intoFirebirdSQL:masterfrom
Noremos:metacache_package_constants

Conversation

@Noremos
Copy link
Copy Markdown
Contributor

@Noremos Noremos commented Feb 25, 2026

Package Constants

This PR adds a new database object - Package Constant (#1036). It is a constant value located in a package header (public visibility) or a package body (private visibility). See README.packages.txt for more information.

SYNTAX

Creation:

CREATE PACKAGE <package_name>
AS
BEGIN
    CONSTANT <constant_name> <type> = <constant_expr>; -- public constant
    -- package routines
END

CREATE PACKAGE BODY <package_name>
AS
BEGIN
    CONSTANT <constant_name> <type> = <constant_expr>; -- private constant
    -- package routines
END

<constant_expr> is an expression that remains unchanged after recompilation.

ackage constants can be queried using the expression <package_name>.<consatnt_name> outside the package (<consatnt_name> must be a public constant) and using the expression <consatnt_name> inside the package.
To query a constant, the user/role must have USAGE permission on the package.

Other SQL extensions:

COMMENT ON CONSTANT [<schema>.]<package>.<const_name> IS <text>
GRANT USAGE ON PACKAGE  [<schema>.]<package_name> to [<user|role>] <name> [<grant_option>] [<granted_by>]
REVOKE USAGE ON PACKAGE  [<schema>.]<package_name> FROM <user|role> <name> [<granted_by>]
SHOW CONST[ANTS]  [ [<schema>.]<package_name> ] -- isql only

Usage examples:

set autoterm;
CREATE PACKAGE MY_PACKAGE
AS
BEGIN
    CONSTANT PUBLIC_CONST INTEGER = 10;
    FUNCTION MY_SECRET_PRINT() RETURNS INT;
END;

CREATE PACKAGE BODY MY_PACKAGE
AS
BEGIN
    CONSTANT SECRET_1 INTEGER = 15;
    CONSTANT SECRET_2 INTEGER = 30;

    FUNCTION MY_SECRET_PRINT() RETURNS INT
    AS
    BEGIN
        RETURN SECRET_1 * SECRET_2;
    END
END;
commit;

select MY_PACKAGE.PUBLIC_CONST from rdb$database ;
select MY_PACKAGE.MY_SECRET_PRINT() from rdb$database;

System Constants

As an exmaple, 3 consatnts have been added to the RDB$BLOB_UTIL package

FROM_BEGIN  : INTEGER = 0
FROM_CURRENT : INTEGER = 1
FROM_END : INTEGER = 2

System metadata changes

New system table - RDB$CONSTANTS

Table: SYSTEM.RDB$CONSTANTS
RDB$CONSTANT_NAME               (SYSTEM.RDB$FIELD_NAME) CHAR(63) CHARACTER SET SYSTEM.UTF8 Nullable 
RDB$CONSTANT_ID                 (SYSTEM.RDB$CONSTANT_ID) INTEGER Nullable 
RDB$PACKAGE_NAME                (SYSTEM.RDB$PACKAGE_NAME) CHAR(63) CHARACTER SET SYSTEM.UTF8 Nullable 
RDB$FIELD_SOURCE                (SYSTEM.RDB$FIELD_NAME) CHAR(63) CHARACTER SET SYSTEM.UTF8 Nullable 
RDB$PRIVATE_FLAG                (SYSTEM.RDB$SYSTEM_NULLFLAG) SMALLINT Nullable 
RDB$CONSTANT_BLR                (SYSTEM.RDB$CONSTANT_BLR) BLOB segment 80, subtype BLR Nullable 
RDB$CONSTANT_SOURCE             (SYSTEM.RDB$SOURCE) BLOB segment 80, subtype TEXT CHARACTER SET SYSTEM.UTF8 Nullable 
RDB$SCHEMA_NAME                 (SYSTEM.RDB$SCHEMA_NAME) CHAR(63) CHARACTER SET SYSTEM.UTF8 Nullable 
RDB$DESCRIPTION                 (SYSTEM.RDB$DESCRIPTION) BLOB segment 80, subtype TEXT CHARACTER SET SYSTEM.UTF8 Nullable 
CONSTRAINT RDB$INDEX_98:
  Unique key (RDB$SCHEMA_NAME, RDB$PACKAGE_NAME, RDB$CONSTANT_NAME)
CONSTRAINT RDB$INDEX_99:
  Unique key (RDB$CONSTANT_ID)

A new field has been added to RDB$PACKAGES - RDB$PACKAGE_ID

New indexes:

Unique key SYSTEM.RDB$CONSTANTS  (RDB$SCHEMA_NAME, RDB$PACKAGE_NAME, RDB$CONSTANT_NAME)
Unique key SYSTEM.RDB$CONSTANTS (RDB$CONSTANT_ID)
Unique key SYSTEM.RDB$PACKAGES (RDB$PACKAGE_ID)

Implementation

Packages have been added to the metacaching system. Since it relies heavily on identifiers, a new ID field (RDB$PACKAGE_ID) has been added to the RDB$PACKAGES table. Constants are stored as an array in the package metacaching object, with a package_id-to-array_id and constant_name-to-array_id mappings.

There are also two important points:

  1. All nodes now have an 'is constant' flag, similar to the 'is deterministic' flag. This is necessary to determine whether an expression can initialize a constant.
  2. In the CreateAlterPackageNode node, a lot of code had to be copied and pasted, and adding constants led to complete chaos. Therefore, I decided to slightly refactor this node. All functionality remains the same; only code duplication was removed.

@sim1984
Copy link
Copy Markdown
Contributor

sim1984 commented Feb 25, 2026

Are comments supported for constants? I didn't see this in the documentation.
Let me clarify what I mean:

COMMENT ON CONSTANT [<schema>.]<package>.<const_name> IS 'Text'

Comments are simply supported for packaged procedures and functions. It would make sense to do the same for constants (and any package objects, for that matter).

COMMENT ON PROCEDURE [<schema>.]<package>.<proc_name> IS 'Text';
COMMENT ON FUNCTION [<schema>.]<package>.<func_name> IS 'Text';

@Noremos
Copy link
Copy Markdown
Contributor Author

Noremos commented Feb 25, 2026

Are comments supported for constants?

No, I didn't plan to implement comments, but I think it's possible. I will take a look

@Noremos
Copy link
Copy Markdown
Contributor Author

Noremos commented Apr 2, 2026

Aren't system packages created during database creation itself? I.e. even during restore they will be created first, before user packages.

I think the original question was about a situation where there are 4 systemp packages, 1 user packages and a new version adds a new system package. If you preserve the original ID when restoring, the following situation will occur

TimeZonePackage: ID 1
ProfilerPackage: ID 2
BlobUtilPackage: ID 3
SqlPackage: ID 4 
NewSystemPackage: ID 5
UerPackage: ID 5 <- restored package

But the IDs are regenerated, so we are safe.

@sim1984
Copy link
Copy Markdown
Contributor

sim1984 commented Apr 2, 2026

Aren't system packages created during database creation itself? I.e. even during restore they will be created first, before user packages.

I think the original question was about a situation where there are 4 systemp packages, 1 user packages and a new version adds a new system package. If you preserve the original ID when restoring, the following situation will occur

TimeZonePackage: ID 1
ProfilerPackage: ID 2
BlobUtilPackage: ID 3
SqlPackage: ID 4 
NewSystemPackage: ID 5
UerPackage: ID 5 <- restored package

But the IDs are regenerated, so we are safe.

Yes, that's exactly what I was asking about. Thanks for clarifying.

@aafemt
Copy link
Copy Markdown
Contributor

aafemt commented Apr 2, 2026

None of IDs are persistent in Firebird and there is no reason for package's one to be the first.

@sim1984
Copy link
Copy Markdown
Contributor

sim1984 commented Apr 2, 2026

None of IDs are persistent in Firebird and there is no reason for package's one to be the first.

This isn't true for relations. That's why I asked.

@Noremos
Copy link
Copy Markdown
Contributor Author

Noremos commented Apr 2, 2026

Hmm, I thought that since constants aren't independent objects, it would be enough if the user had permission to create a package. Should I add separate permissions for creating constants?

I'm referring to the outside user of a constant, which should have permission to use the package.

I've added permission checking

connect employee user R;
Database: employee, User: R

SQL> select TEST.C1 from rdb$database;
Statement failed, SQLSTATE = 28000
no permission for USAGE access to PACKAGE "PUBLIC"."TEST"
-Effective user is R

To grant permissions:
grant USAGE on package TEST to user R;
To revoke permissions:
revoke usage on package TEST from user R;


FOR (REQUEST_HANDLE req_handle1)
CONST IN RDB$CONSTANTS
WITH CONST.RDB$SCHEMA_NAME NE SYSTEM_SCHEMA
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this check allowed or should I add the RDB$SYSTEM_FLAG field?

Copy link
Copy Markdown
Contributor Author

@Noremos Noremos left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this PR is ready to rereviw @AlexPeshkoff @asfernandes @dyemanov


bool isPrivate = !CONST.RDB$PRIVATE_FLAG.NULL && CONST.RDB$PRIVATE_FLAG;

if (!CONST.RDB$PACKAGE_NAME.NULL)
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I removed the checks for now

src/jrd/obj.h Outdated
case obj_schemas:
return "SQL$SCHEMAS";
case obj_package_constant:
return "SQL$PACKAGE_CONSTANT";
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I removed it for now

class SysFunction
{
public:
enum Flags : UCHAR
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I remvoed the NONE

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants